<template>
  <div class=main :id=div_id>
    <canvas :id=canvas_id ref="canvasRef"></canvas>
  </div>
</template>

<script lang="ts" setup>
import { defineExpose, defineProps, getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue'
import { v4 as uuidv4 } from 'uuid'
import type {WorkerMessage, ProcessedData} from './spectrum-view.worker'

// 初始化 Worker（网页4）
const worker = new Worker(new URL("./spectrum-view.worker.ts", import.meta.url), {
  type: 'module', // 必须声明模块类型
});


let canvas_id = uuidv4()
let div_id = uuidv4()

let resizeObserver: ResizeObserver | null = null;

const proxy = getCurrentInstance()
const props = defineProps({
  chooseShow: {
    type: Boolean,
    default: false,
    required: false //是否必传
  },
  showMode : {
    type: Number,
    default: 5,
    required: false //是否必传
  },
})
/**
 * 选择区域
 */
interface SelectRange {
  start: number,
  end: number,
}

/**
 * 频率范围
 */
 interface FreqRange {
  left: number,
  right: number,
}

/**
 * 电平范围
 */
 interface LevelRange {
  top: number,
  bottom: number,
}

class ViewRect {
  left: number;
  right: number;
  top: number;
  bottom: number;
  width: number;
  height: number;
  constructor(left: number, right: number, top: number, bottom: number) {
    this.left = left
    this.right = right
    this.top = top
    this.bottom = bottom
    this.width = right - left;
    this.height = bottom - top;
  }
}

interface DrawPoint{ 
  x: number; 
  y: number 
};

enum ShowModeEnum {
  FFT = 1, //'频域图'
  WAVE = 2, //'时域图'
  FULL = 3, //'瀑布图'
  FFT_WAVE = 4, //'频域+时域图'
  FFT_FULL = 5, //'频域+瀑布图'
}


let showMode: ShowModeEnum = 5;   // 显示类型
let fftRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 频域图区域
let freqRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 频率刻度区域
let levelRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 电平刻度区域
let fullRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 瀑布图区域
let legendRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 图例区域
let waveRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 波形图区域
let leftPadding: number = 10;
let rightPadding: number = 50;
let topPadding: number = 10;
let bottomPadding: number = 25;

let freqRange: FreqRange = { left: 0, right: 1000 }; // 频率范围
let showFreqRange: FreqRange = { left: 0, right: 1000 }; // 显示频率范围
let levelRange: LevelRange = { top: 20, bottom: -170 }; // 电平范围
let showLevelRange: LevelRange = { top: 20 ,bottom: -170 }; // 显示电平范围
let fftHeaps: boolean = true; // 频域图堆积

let minWav: number = -16384;
let maxWav: number = 16384;
let rowNum: number = 5; // 行
let cloumnNum: number = 5; // 列
let maindiv = ref();
let painter: CanvasRenderingContext2D | null = null; //
let canvas = ref<HTMLCanvasElement | null>(null); // 画布

// 接收处理结果
const fftPoints = ref<Array<DrawPoint>>([]); // fft数据
const maxFftPoints = ref<Array<DrawPoint>>([]);// fft最大值数据
const waterfallImage = ref<ImageBitmap>();
let waveData: number[] = [];
let chooseShow: boolean = false;
let chooseIng = false;
let selectRanges: SelectRange[] = [];
let chooseBeginFreq: number = 0;
let chooseEndFreq: number = 0;
let mouseBeginX: number = 0; // 鼠标按下点
let mouseBeginY: number = 0; // 鼠标按下点
let mouseHoverX: number = 0; // 鼠标悬浮坐标点X
let mouseHoverY: number = 0;
let mouseEndX: number = 0; // 鼠标弹起点X
let mouseEndY: number = 0; // 鼠标弹起点X
let selectFreq: boolean = false;
let moveFreq: boolean = false;
let selectLevel: boolean = false;
let moveLevel: boolean = false;
let subLineShow: boolean = true;//辅助线显示功能开启
let subXLineShow: boolean = false;//电平辅助线显示
let subYLineShow: boolean = false;//频率辅助线显示
let nowFreq: number = 0;
let nowLevel: number = 0;

let isPainting = false;


watch(() => props.showMode, (newVal) => {
  setShowMode(newVal)
})


worker.onmessage = (({ data }: MessageEvent<WorkerMessage>)=> {
  if (data.type === 'processedData') {
    // console.log('receive processedData',spectrumData.value)
    fftPoints.value = data.payload.fftPoints
    maxFftPoints.value = data.payload.maxFftPoints
    waterfallImage.value = data.payload.imageBitmap
    paint()
  } 
});

// 发送显示频率范围到worker
const sendShowFreqRange = (range: FreqRange) => {
  showFreqRange = range
  worker.postMessage({
    type: 'setShowFreqRange',
    payload: showFreqRange
  });
}

// 发送显示电平范围到worker
const sendShowLevelRange = (range: LevelRange) => {
  showLevelRange = range
  worker.postMessage({
    type: 'setShowLevelRange',
    payload: showLevelRange
  });
}

// 发送频域数据到worker
const sendFftData = (data: number[], startFreq: number, stopFreq: number) => {
  worker.postMessage({
    type: 'setFftData',
    payload: {
      data,
      startFreq: startFreq,
      stopFreq: stopFreq
    }
  });
};

// 发送频域图区域到worker
const sendFftRect = (viewRect: ViewRect) => {
  worker.postMessage({
    type: 'setFftRect',
    payload: viewRect
  });
};

// 发送是否计算最大值到worker
const sendComputeMaxFft = (computeMaxFft: boolean) => {
  worker.postMessage({
    type: 'setComputeMaxFft',
    payload: {
      computeMaxFft: computeMaxFft
    }
  });
}


// 设置显示类型
const setShowMode = (mode: number) => {
  showMode = mode
  resetRect();
}

// 设置是否fft最大值保持
const setFftHeaps = (value: boolean) => {
  fftHeaps = value
  sendComputeMaxFft(fftHeaps)
}

// fft数据更新
const appendFftData = (data: number[], startFreq: number, stopFreq: number) => {
  sendFftData(data, startFreq, stopFreq);
}

// 波形数据更新
const appendWaveData = (data: number[]) => {
  waveData = data
  paint()
}

let setChooseFreq = (leftFreq: number, rightFreq: number) => {
  chooseBeginFreq = leftFreq
  chooseEndFreq = rightFreq
  chooseShow = true
  paint()
}

// 频率范围更新
const setFreqRange = (range: FreqRange) => {
  if (range.left !== freqRange.left || range.right !== freqRange.right) {
    freqRange = range
    showFreqRange = range

    sendShowFreqRange(showFreqRange)
    paint()
  }
}


// 重置画布
const resetRect = () => {
  const canvasElement = canvas.value;
  if (canvasElement) {
    canvasElement.width = document.getElementById(div_id)?.clientWidth as number
    canvasElement.height = document.getElementById(div_id)?.clientHeight as number

    // 全部归0
    fftRect = new ViewRect(0, 0, 0, 0)
    freqRect = new ViewRect(0, 0, 0, 0)
    levelRect = new ViewRect(0, 0, 0, 0)
    waveRect = new ViewRect(0, 0, 0, 0)
    fullRect = new ViewRect(0, 0, 0, 0)
    legendRect = new ViewRect(0, 0, 0, 0)
    // 
    if (showMode === ShowModeEnum.FFT) {
      fftRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, topPadding, canvasElement.height - bottomPadding)
      freqRect = new ViewRect(fftRect.left, fftRect.right, fftRect.bottom, canvasElement.height)
      levelRect = new ViewRect(fftRect.right, canvasElement.width, fftRect.top, fftRect.bottom)
    } else if (showMode === ShowModeEnum.WAVE) {
      waveRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, topPadding, canvasElement.height - bottomPadding)
    } else if (showMode === ShowModeEnum.FULL) {
      fullRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, topPadding, canvasElement.height - bottomPadding)
      legendRect = new ViewRect(fullRect.right, canvasElement.width, fullRect.top, fullRect.bottom)
    } else if (showMode === ShowModeEnum.FFT_WAVE) {
      fftRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, topPadding, canvasElement.height / 2 - bottomPadding)
      freqRect = new ViewRect(fftRect.left, fftRect.right, fftRect.bottom, canvasElement.height / 2)
      levelRect = new ViewRect(fftRect.right, canvasElement.width, fftRect.top, fftRect.bottom)
      waveRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, canvasElement.height / 2 + topPadding, canvasElement.height - bottomPadding)
    } else if (showMode === ShowModeEnum.FFT_FULL) {
      fftRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, topPadding, canvasElement.height / 2 - bottomPadding);
      freqRect = new ViewRect(fftRect.left, fftRect.right, fftRect.bottom, canvasElement.height / 2);
      levelRect = new ViewRect(fftRect.right, canvasElement.width, fftRect.top, fftRect.bottom);
      fullRect = new ViewRect(leftPadding, canvasElement.width - rightPadding, canvasElement.height / 2 + topPadding, canvasElement.height - bottomPadding);
      legendRect = new ViewRect(fullRect.right, canvasElement.width, fullRect.top, fullRect.bottom);
    }
  }
  sendFftRect(fftRect);
  paint()
}




const drawFft = () => {
  if (!painter) return;
  painter.save()
  painter.strokeStyle = '#f5d37f'
  painter.lineWidth = 1
  painter.beginPath()

  // const start = performance.now();
  // 画频域图
  for (let i = 1; i < fftPoints.value.length; i++) {
    painter.moveTo(fftPoints.value[i-1].x, fftPoints.value[i-1].y);
    painter.lineTo(fftPoints.value[i].x, fftPoints.value[i].y);
  }
  // canvasElement.clipRect(0, 0, canvasElement.width, canvasElement.height)
  painter.rect(fftRect.left, fftRect.top, fftRect.width, fftRect.height)
  painter.clip()
  painter.closePath()
  painter.stroke()
  painter.restore()
  // const end = performance.now();
  // console.log(`FFT绘制时间: ${end - start} ms`);
}

const drawMaxFft = () => {
  if( !fftHeaps ) return
  if( !painter ) return;
  if( !maxFftPoints.value ) return;
  painter.save()
  painter.strokeStyle = 'green'
  painter.lineWidth = 1
  painter.beginPath()

  // const start = performance.now();
  for (let i = 1; i < maxFftPoints.value.length; i++) {
    painter.moveTo(maxFftPoints.value[i-1].x, maxFftPoints.value[i-1].y);
    painter.lineTo(maxFftPoints.value[i].x, maxFftPoints.value[i].y);
  }
  // canvasElement.clipRect(0, 0, canvasElement.width, canvasElement.height)
  painter.rect(fftRect.left, fftRect.top, fftRect.width, fftRect.height)
  painter.clip()
  painter.closePath()
  painter.stroke()
  painter.restore()
  // const end = performance.now();
  // console.log(`最大值FFT绘制时间: ${end - start} ms`);
}

const drawLegend = () => {
  if (!painter) return
  painter.save()
  let grad = painter.createLinearGradient(0, legendRect.top, 0, legendRect.bottom)
  grad.addColorStop(0, 'rgb(0,0,0)')
  grad.addColorStop(1, 'rgb(255,255,255)')
  painter.fillStyle = grad
  painter.fillRect(legendRect.left + legendRect.width / 4, legendRect.top, legendRect.width / 2, legendRect.height)
  painter.fillStyle = ""
  painter.restore()
}
const drawFull = () => {
  if (!painter) return
  if(waterfallImage.value)
    painter.drawImage(waterfallImage.value, fullRect.left, fullRect.top, fullRect.width, fullRect.height)
}
const drawWave = () => {
  if (!painter) return;
  painter.save()
  painter.strokeStyle = '#f5d37f'
  painter.lineWidth = 1
  painter.beginPath()
  // canvasElement.clipRect(fftRect.left, fftRect.top, fftRect.width, fftRect.height)
  let step = waveData.length / waveRect.width
  for (let i = 1; i < waveData.length; i++) {
    painter.moveTo((i - 1) * step,
      (maxWav - waveData[i - 1]) / (maxWav - minWav) * waveRect.height + waveRect.top)
    painter.lineTo(i * step,
      (maxWav - waveData[i]) / (maxWav - minWav) * waveRect.height + waveRect.top)
  }
  painter.rect(waveRect.left, waveRect.top, waveRect.width, waveRect.height)
  painter.clip()
  painter.closePath()
  painter.stroke()
  painter.restore()
}
const drawWaveGrid = () => {
  if (!painter) return;
  painter.save()
  painter.strokeStyle = canvas.value?.style.color as string;
  painter.lineWidth = 0.5
  painter.beginPath()

  // 画横线
  for (let i = 0; i <= rowNum; i++) {
    painter.moveTo(waveRect.left, waveRect.height / rowNum * i + waveRect.top)
    painter.lineTo(waveRect.right, waveRect.height / rowNum * i + waveRect.top)
  }
  painter.stroke()
  painter.closePath()
  painter.restore()
}
const measureText = (font: string, text: string) => {
  let spanDom = document.createElement('span')
  spanDom.style.margin = '0'
  spanDom.style.font = font
  spanDom.style.opacity = '0'
  spanDom.innerHTML = text
  document.body.append(spanDom)
  let sizeD: { width: number; height: number; } = { width: 0, height: 0 }
  sizeD.width = spanDom.offsetWidth
  sizeD.height = spanDom.offsetHeight / 2
  spanDom.remove()
  return sizeD
}

function hslToRgb(h: number, s: number, l: number): [number, number, number] {
  s /= 100;
  l /= 100;

  const k = (n: number) => (n + h / 30) % 12;
  const a = s * Math.min(l, 1 - l);
  const f = (n: number) =>
    l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));

  return [f(0) * 255, f(8) * 255, f(4) * 255];
}

function parseHslString(hslString: string): [number, number, number] | null {
  const match = hslString.match(/hsl$(\d+),\s*(\d+)%,\s*(\d+)%$/i);
  if (!match) return null;

  const [h, s, l] = match.slice(1).map(Number);
  return [h, s, l];
}

function getRootCssVariable(variable: string): string | null {
  const root = document.documentElement; // <html> 元素
  return window.getComputedStyle(root).getPropertyValue(variable).trim() || null;
}

const drawFreq = () => {
  if (!painter) return;
  painter.strokeStyle = '#f8fafa'
  painter.fillStyle = '#f8fafa'
  for (let i = 0; i <= cloumnNum; i++) {
    let freqStr = (showFreqRange.left + (showFreqRange.right - showFreqRange.left) / cloumnNum * i).toFixed(2) + 'Hz'
    let halfwidth = painter.measureText(freqStr).width / 2
    let halfHeight = measureText(painter.font, freqStr).height
    if (i === 0) {
      painter.fillText(freqStr, fftRect.left, fftRect.bottom + halfHeight, painter.measureText(freqStr).width)
    } else {
      painter.fillText(freqStr, fftRect.width / cloumnNum * i + leftPadding - halfwidth, fftRect.bottom + halfHeight, painter.measureText(freqStr).width)
      // painter.strokeText(freqStr, fftRect.width / cloumnNum * i + leftPadding, canvasElement.height - bottomPadding, painter.measureText(freqStr).width)
    }
  }
}
const drawLevel = () => {
  if (!painter) return;
  painter.strokeStyle = '#f8fafa'
  painter.fillStyle = '#f8fafa'
  for (let i = 0; i <= rowNum; i++) {
    let levelStr = (showLevelRange.top - (showLevelRange.top - showLevelRange.bottom) / rowNum * i).toFixed(1) + ' dBm'
    let halfHeight = measureText(painter.font, levelStr).height / 2
    if (i === rowNum) {
      painter.fillText(levelStr, fftRect.right, fftRect.bottom, painter.measureText(levelStr).width)
    } else {
      painter.fillText(levelStr, fftRect.right, fftRect.height / rowNum * i + topPadding + halfHeight, painter.measureText(levelStr).width)
      // painter.strokeText(freqStr, fftRect.width / cloumnNum * i + leftPadding, canvasElement.height - bottomPadding, painter.measureText(freqStr).width)
    }
  }
}

const freqToPx = (freq: number) => {
  return (freq - showFreqRange.left) / (showFreqRange.right - showFreqRange.left) * fftRect.width + leftPadding
}

const levelToPx = (level: number) => {
  return (showLevelRange.top - level) / (showLevelRange.top - showLevelRange.bottom) * fftRect.height + topPadding
}

const drawChoose = () => {
  if (!painter) return;
  painter.save()
  let startX = (chooseBeginFreq - showFreqRange.left) / (showFreqRange.right - showFreqRange.left) * fftRect.width + fftRect.left
  let endX = (chooseEndFreq - showFreqRange.left) / (showFreqRange.right - showFreqRange.left) * fftRect.width + fftRect.left
  // 创建一个渐变色线性对象
  let grad = painter.createLinearGradient(startX > endX ? endX : startX, 0, startX > endX ? startX : endX, 0)
  // 设置渐变颜色
  grad.addColorStop(0, 'rgba(22,184,200,0.47)')
  grad.addColorStop(0.5, 'rgba(82,67,192,0.47)')
  grad.addColorStop(1, 'rgba(22,184,200,0.47)')
  // 设置fillStyle为当前的渐变对象
  painter.fillStyle = grad
  // 绘制渐变图形
  painter.fillRect(startX > endX ? endX : startX, fftRect.top, Math.abs(endX - startX), fftRect.height)
  painter.fillStyle = ""
  painter.restore()
}
const drawSelectFreq = () => {
  if (!painter) return;
  painter.save()
  painter.fillStyle = 'rgba(73,114,248,0.87)'
  painter.fillRect(mouseBeginX, fftRect.top, mouseEndX - mouseBeginX, fftRect.height + freqRect.height)
  painter.fillStyle = ""
  painter.restore()
}
const drawSelectLevel = () => {
  if (!painter) return;
  painter.save()
  painter.fillStyle = 'rgba(73,114,248,0.87)'
  painter.fillRect(leftPadding, mouseBeginY, freqRect.width + levelRect.width, mouseEndY - mouseBeginY)
  painter.fillStyle = ""
  painter.restore()
}
const drawFftGrid = () => {
  if (!painter) return;
  painter.save()
  painter.strokeStyle = '#cfd9da'
  painter.lineWidth = 0.5
  painter.beginPath()

  // 画横线
  for (let i = 0; i <= rowNum; i++) {
    painter.moveTo(fftRect.left, fftRect.height / rowNum * i + fftRect.top)
    painter.lineTo(fftRect.right, fftRect.height / rowNum * i + fftRect.top)
  }

  // 画纵线
  for (let i = 0; i <= cloumnNum; i++) {
    painter.moveTo(fftRect.width / cloumnNum * i + fftRect.left, fftRect.top)
    painter.lineTo(fftRect.width / cloumnNum * i + fftRect.left, fftRect.bottom)
  }
  painter.stroke()
  painter.closePath()
  painter.restore()
}
const drawSubLine = () => {
  if (!painter) return;
  painter.save()
  painter.strokeStyle = '#EB3324'
  painter.lineWidth = 1
  painter.beginPath()

  let freqStr = '频率：' + nowFreq.toFixed(2) + ' Hz'
  let levelStr = '电平：' + nowLevel.toFixed(2) + ' dBm'

  if (subXLineShow) {
    painter.moveTo(fftRect.left, mouseHoverY)
    painter.lineTo(levelRect.right, mouseHoverY)
    painter.fillText(levelStr, fftRect.left, fftRect.bottom - 8, painter.measureText(levelStr).width)
  }

  if (subYLineShow) {
    painter.moveTo(mouseHoverX, fftRect.top)
    painter.lineTo(mouseHoverX, freqRect.bottom)
    painter.fillText(freqStr, fftRect.left, fftRect.bottom - 20, painter.measureText(freqStr).width)
  }
  painter.stroke()
  painter.closePath()
  painter.restore()
}

const paint = () => {
  if(isPainting) return;
  // const start = performance.now();
  isPainting = true;
  if (painter && canvas.value) {
    painter.clearRect(0, 0, canvas.value.width, canvas.value.height)
  }

  // drawFreqBand()
  if (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) drawFftGrid()
  if (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) drawFft()
  if (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) drawMaxFft();
  if (chooseShow) drawChoose()
  if (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) drawFreq()
  if (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) drawLevel()
  if (selectFreq) drawSelectFreq()
  if (selectLevel) drawSelectLevel()
  if (showMode === ShowModeEnum.FULL || showMode === ShowModeEnum.FFT_FULL) drawLegend()
  if (showMode === ShowModeEnum.FULL || showMode === ShowModeEnum.FFT_FULL) drawFull()
  if (showMode === ShowModeEnum.WAVE || showMode === ShowModeEnum.FFT_WAVE) drawWave()
  if (showMode === ShowModeEnum.WAVE || showMode === ShowModeEnum.FFT_WAVE) drawWaveGrid()
  if (subLineShow) drawSubLine()
  isPainting = false;
  // const end = performance.now();
  // console.log(`==================重绘时间: ${end - start} ms`);
}
// 封装的scrollTop
const scroll = () => {
  if (window.pageYOffset != null) { // ie9+ 高版本浏览器
    // 因为 window.pageYOffset 默认的是  0  所以这里需要判断
    return {
      left: window.pageXOffset,
      top: window.pageYOffset
    }
  } else if (document.compatMode === 'CSS1Compat') { // 标准浏览器   来判断有没有声明DTD
    return {
      left: document.documentElement.scrollLeft,
      top: document.documentElement.scrollTop
    }
  }
  return { // 未声明 DTD
    left: document.body.scrollLeft,
    top: document.body.scrollTop
  }
}
const canvasDown = (e: { clientX: number; clientY: number; button: number; }) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseBeginX = e.clientX - canvasRect.x
  mouseBeginY = e.clientY - canvasRect.y
  mouseEndX = mouseBeginX
  mouseEndY = mouseBeginY
  if (e.button === 0 && mouseBeginX > fftRect.left && mouseBeginX < fftRect.right && mouseBeginY > fftRect.top && mouseBeginY < fftRect.bottom) {
    chooseIng = true
    chooseShow = true
    chooseBeginFreq = (mouseBeginX - fftRect.left) / fftRect.width * (showFreqRange.right - showFreqRange.left) + showFreqRange.left
  }
  if (mouseBeginX > freqRect.left && mouseBeginX < freqRect.right && mouseBeginY > freqRect.top && mouseBeginY < freqRect.bottom) {
    if (e.button === 2) {
      selectFreq = true
    } else if (e.button === 0) {
      moveFreq = true
    }
  }
  if (mouseBeginX > levelRect.left && mouseBeginX < levelRect.right && mouseBeginY > levelRect.top && mouseBeginY < levelRect.bottom) {
    if (e.button === 2) {
      selectLevel = true
    } else if (e.button === 0) {
      moveLevel = true
    }
  }
}
const canvasMove = (e: { clientX: number; clientY: number; }) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseHoverX = e.clientX - canvasRect.x
  mouseHoverY = e.clientY - canvasRect.y
  mouseEndX = mouseHoverX
  mouseEndY = mouseHoverY

  if (subLineShow && (showMode === ShowModeEnum.FFT || showMode === ShowModeEnum.FULL || showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL)) {
    let wanthFreq = Math.abs(showFreqRange.left - showFreqRange.right);
    nowFreq = showFreqRange.left + ((mouseHoverX - leftPadding) / fftRect.width) * wanthFreq;
  }
  if (subLineShow && showMode === ShowModeEnum.FFT) { // 全FFT时计算电平
    let wanthLevel = Math.abs(showLevelRange.top - showLevelRange.bottom);
    nowLevel = showLevelRange.top - wanthLevel * (mouseHoverY - topPadding) / fftRect.height;
  }

  if (showMode === ShowModeEnum.FFT_WAVE || showMode === ShowModeEnum.FFT_FULL) { //一半fft时计算电平
    let wanthLevel = Math.abs(showLevelRange.top - showLevelRange.bottom);
    nowLevel = showLevelRange.top - wanthLevel * (mouseHoverY - topPadding) / (fftRect.height / 2);
  }

  if (mouseHoverX > fftRect.left && mouseHoverX < fftRect.right && mouseHoverY > fftRect.top && mouseHoverY < freqRect.bottom) {
    subYLineShow = true;
  } else {
    subYLineShow = false;
  }

  if (mouseHoverX > fftRect.left && mouseHoverX < levelRect.right && mouseHoverY > fftRect.top && mouseHoverY < fftRect.bottom) {
    subXLineShow = true;
  } else {
    subXLineShow = false;
  }


  if (chooseIng) {
    chooseEndFreq = (mouseEndX - fftRect.left) / fftRect.width * (showFreqRange.right - showFreqRange.left) + showFreqRange.left
  }
  if (moveFreq) {
    let moveVal = (showFreqRange.right - showFreqRange.left) / freqRect.width * (mouseBeginX - mouseEndX)
    if (showFreqRange.left + moveVal >= freqRange.left && showFreqRange.right + moveVal <= freqRange.right) {
      showFreqRange.left += moveVal
      showFreqRange.right += moveVal
      sendShowFreqRange({ left:showFreqRange.left, right:showFreqRange. right});
    }
    mouseBeginX = mouseEndX
    mouseBeginY = mouseEndY
  }
  if (moveLevel) {
    let moveVal = (showLevelRange.top - showLevelRange.bottom) / levelRect.height * (mouseEndY - mouseBeginY)
    if (showLevelRange.top + moveVal <= levelRange.top && showLevelRange.bottom + moveVal >= levelRange.bottom) {
      showLevelRange.top += moveVal
      showLevelRange.bottom += moveVal
      sendShowLevelRange({ bottom:showLevelRange.bottom, top:showLevelRange.top});
    }
    mouseBeginX = mouseEndX
    mouseBeginY = mouseEndY
  }
  //if (selectFreq || selectLevel || chooseIng || moveFreq || moveLevel)
  // paint()
}
const canvasUp = (e: { clientX: number; clientY: number; }) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseEndX = e.clientX - canvasRect.x
  mouseEndY = e.clientY - canvasRect.y
  if (chooseIng) {
    chooseEndFreq = (mouseEndX - fftRect.left) / fftRect.width * (showFreqRange.right - showFreqRange.left) + showFreqRange.left
    if (chooseEndFreq < chooseBeginFreq) {
      let freq = chooseEndFreq
      chooseEndFreq = chooseBeginFreq
      chooseBeginFreq = freq
    }
    if (chooseEndFreq === chooseBeginFreq) {
      chooseShow = false
    } else {
      // 发送信号
      // proxy.emit('chooseFreqChange', chooseBeginFreq, chooseEndFreq)
    }
    // alert('框选开始频率:' + chooseBeginFreq + '框选结束频率' + chooseEndFreq)
  }
  if (selectFreq) {
    let beginFreq = (mouseBeginX > mouseEndX ? mouseEndX : mouseBeginX - freqRect.left) 
    / freqRect.width * (showFreqRange.right - showFreqRange.left) + showFreqRange.left
    let endFreq = (mouseBeginX > mouseEndX ? mouseBeginX : mouseEndX - freqRect.left) 
    / freqRect.width * (showFreqRange.right - showFreqRange.left) + showFreqRange.left
    sendShowFreqRange({ left:beginFreq,right:endFreq});
  }
  if (selectLevel) {
    let newBottom = showLevelRange.top - (mouseBeginY > mouseEndY ? mouseBeginY : mouseEndY - levelRect.top) 
    / levelRect.height * (showLevelRange.top - showLevelRange.bottom)
    let newTop = showLevelRange.top - (mouseBeginY > mouseEndY ? mouseEndY : mouseBeginY - levelRect.top) 
    / levelRect.height * (showLevelRange.top - showLevelRange.bottom)
    showLevelRange.bottom = newBottom
    showLevelRange.top = newTop
    sendShowLevelRange({ bottom:showLevelRange.bottom, top:showLevelRange.top});
  }
  chooseIng = false
  selectFreq = false
  moveFreq = false
  selectLevel = false
  moveLevel = false
  paint()
}
const canvasDblClick = (e: { button: number; }) => {
  // 重置频率区域
  if (e.button === 0 && mouseHoverX > freqRect.left && mouseHoverX < freqRect.right && mouseHoverY > freqRect.top && mouseHoverY < freqRect.bottom) {
    sendShowFreqRange({left:freqRange.left,right:freqRange.right});
    paint()
  }
  // 重置电平区域
  if (e.button === 0 && mouseHoverX > levelRect.left && mouseHoverX < levelRect.right && mouseHoverY > levelRect.top && mouseHoverY < levelRect.bottom) {
    showLevelRange.bottom = levelRange.bottom
    showLevelRange.top = levelRange.top
    paint()
  }
}
const canvasWheel = (e: any) => {
  if (e.wheelDelta > 0 || e.detail < 0) {
    if (mouseHoverX > freqRect.left && mouseHoverX < freqRect.right && mouseHoverY > freqRect.top && mouseHoverY < freqRect.bottom) {
      let changeVal = (showFreqRange.right - showFreqRange.left) / 10
      let changeLeftVal = (mouseHoverX - freqRect.left) / freqRect.width * changeVal
      let changeRightVal = changeVal - changeLeftVal
      showFreqRange.left += changeLeftVal
      showFreqRange.right -= changeRightVal
      sendShowFreqRange({ left:showFreqRange.left, right:showFreqRange.right});
    }
    if (mouseHoverX > levelRect.left && mouseHoverX < levelRect.right && mouseHoverY > levelRect.top && mouseHoverY < levelRect.bottom) {
      let changeVal = (showLevelRange.top - showLevelRange.bottom) / 10
      let changeTopVal = (mouseHoverY - levelRect.top) / levelRect.height * changeVal
      let changeBottomVal = changeVal - changeTopVal
      showLevelRange.top -= changeTopVal
      showLevelRange.bottom += changeBottomVal
      sendShowLevelRange({ bottom:showLevelRange.bottom, top:showLevelRange.top});
    }
  } else {
    if (mouseHoverX > freqRect.left && mouseHoverX < freqRect.right && mouseHoverY > freqRect.top && mouseHoverY < freqRect.bottom) {
      let changeVal = (showFreqRange.right - showFreqRange.left) / 9
      let changeLeftVal = (mouseHoverX - freqRect.left) / freqRect.width * changeVal
      let changeRightVal = changeVal - changeLeftVal
      if (showFreqRange.left - changeLeftVal < freqRange.left) {
        showFreqRange.left = freqRange.left
      } else {
        showFreqRange.left -= changeLeftVal
      }
      if (showFreqRange.right + changeRightVal > freqRange.right) {
        showFreqRange.right = freqRange.right
      } else {
        showFreqRange.right += changeRightVal
      }
      sendShowFreqRange({ left:showFreqRange.left, right:showFreqRange.right});
    }
    if (mouseHoverX > levelRect.left && mouseHoverX < levelRect.right && mouseHoverY > levelRect.top && mouseHoverY < levelRect.bottom) {
      let changeVal = (showLevelRange.top - showLevelRange.bottom) / 10
      let changeTopVal = (mouseHoverY - levelRect.top) / levelRect.height * changeVal
      let changeBottomVal = changeVal - changeTopVal
      if (showLevelRange.top + changeTopVal > levelRange.top) {
        showLevelRange.top = levelRange.top
      } else {
        showLevelRange.top += changeTopVal
      }
      if (showLevelRange.bottom - changeBottomVal < levelRange.bottom) {
        showLevelRange.bottom = levelRange.bottom
      } else {
        showLevelRange.bottom -= changeBottomVal
      }
      sendShowLevelRange({ bottom:showLevelRange.bottom, top:showLevelRange.top});
    }
  }
  paint()
}
const canvasOver = () => {
  // console.log('移入')
}
const canvasOut = (e: { clientX: number; clientY: number; }) => {
  if (chooseIng) {
    if (canvas.value) {
      mouseEndX = e.clientX - canvas.value.offsetLeft
      mouseEndY = e.clientY - canvas.value.offsetTop
    }
    chooseIng = false
  }
  selectFreq = false
  moveFreq = false
  selectLevel = false
  moveLevel = false
  subXLineShow = false
  subYLineShow = false
}

// 处理尺寸变化的回调函数
const handleResize = (entries: ResizeObserverEntry[]) => {
  for (const entry of entries) {
    if (entry.target === maindiv.value) {
      // 在这里可以添加处理逻辑，例如调整 canvas 尺寸或重新绘制内容
      if (canvas.value) {
        resetRect();
        // 调用绘图函数或其他操作
      }
    }
  }
};

sendShowFreqRange(showFreqRange);
sendShowLevelRange(showLevelRange);
sendComputeMaxFft(fftHeaps);

onMounted(() => {
  maindiv.value = document.getElementById(div_id);
  canvas.value = document.getElementById(canvas_id) as HTMLCanvasElement;
  const canvasElement = canvas.value;
  if (!canvasElement) return;
  canvasElement.width = 200
  canvasElement.height = 100
  painter = canvasElement.getContext('2d')
  if (!painter) return;
  painter.fillStyle = 'rgb(133,155,238)'
  canvasElement.addEventListener('contextmenu', function (e) {
    e.preventDefault()
  })

  canvasElement.addEventListener('mousedown', canvasDown)
  canvasElement.addEventListener('mousemove', canvasMove)
  canvasElement.addEventListener('mouseup', canvasUp)
  canvasElement.addEventListener('dblclick', canvasDblClick)
  canvasElement.addEventListener('mousewheel', canvasWheel)
  canvasElement.addEventListener('mouseover', canvasOver)
  canvasElement.addEventListener('mouseout', canvasOut)

  if (maindiv.value) {
    console.info('创建大小改变监听器');
    resizeObserver = new ResizeObserver(handleResize);
    resizeObserver.observe(maindiv.value);
  } else {
    console.warn('maindiv is not available');
  }

  sendShowFreqRange(showFreqRange);
  sendShowLevelRange(showLevelRange);
  sendComputeMaxFft(fftHeaps);
})

onUnmounted(() => {
  
  // 移除监听器
  if (resizeObserver && maindiv.value) {
    resizeObserver.unobserve(maindiv.value);
    resizeObserver.disconnect();
  }
  
  // 销毁 worker
  if(worker) worker.terminate();
})

defineExpose({
  setFreqRange,//设置坐标开始起止
  setShowMode,//设置显示模式
  setFftHeaps,//设置FFT堆积
  setChooseFreq,//设置框选区域
  appendWaveData,//添加时域数据
  appendFftData,//添加频域数据
  resetRect//调整大小
})
</script>

<style scoped>
.main {
  width: 100%;
  height: 100%;
  background: transparent;
}
</style>
